﻿namespace Neo4jConnect.Test
{
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Neo4jConnect.Plugins;
    using Neo4jConnect.Traversal;

    [TestClass]
    public class MatrixTest : TestBase
    {
        static Node neoNode;
                
        public enum MyRelationshipTypes
        {
            Root,
            Knows,
            CodedBy
        }
        
        void CreateMatrix()
        {
            var graphDb = new GraphDatabaseService(Neo4jUri);

            Node thomas = graphDb.CreateNode();
            thomas.SetProperty("name", "Thomas Anderson");
            thomas.SetProperty("age", "29");
            thomas.Save();

            Node trinity = graphDb.CreateNode();
            trinity.SetProperty("name", "Trinity");
            trinity.Save();

            Node morpheus = graphDb.CreateNode();
            morpheus.SetProperty("name", "Morpheus");
            morpheus.SetProperty("rank", "Captain");
            morpheus.SetProperty("occupation", "Total badass");
            morpheus.Save();

            Node cypher = graphDb.CreateNode();
            cypher.SetProperty("name", "Cypher");
            cypher.SetProperty("last name", "Reagan");
            cypher.Save();

            Node smith = graphDb.CreateNode();
            smith.SetProperty("name", "Agent Smith");
            smith.SetProperty("version", "1.0b");
            smith.SetProperty("language", "C++");
            smith.Save();

            Node architect = graphDb.CreateNode();
            architect.SetProperty("name", "The Architect");
            architect.Save();

            graphDb.GetRootNode().CreateRelationshipTo(thomas, MyRelationshipTypes.Root);

            Relationship rel = null;

            rel = thomas.CreateRelationshipTo(trinity, MyRelationshipTypes.Knows);
            rel.SetProperty("age", "3 days");

            rel = thomas.CreateRelationshipTo(morpheus, MyRelationshipTypes.Knows);

            rel = morpheus.CreateRelationshipTo(trinity, MyRelationshipTypes.Knows);
            rel.SetProperty("age", "12 years");

            rel = morpheus.CreateRelationshipTo(cypher, MyRelationshipTypes.Knows);
            rel.SetProperty("disclosure", "public");

            rel = cypher.CreateRelationshipTo(smith, MyRelationshipTypes.Knows);
            rel.SetProperty("disclosure", "secret");
            rel.SetProperty("age", "6 months");

            rel = smith.CreateRelationshipTo(architect, MyRelationshipTypes.CodedBy);

            neoNode = thomas;            
        }

        [TestInitialize]
        public void TestSetup()
        {
            CreateMatrix();
        }
                
        [TestMethod]
        public void GetAllNodes()
        {
            var graphDb = new GraphDatabaseService(Neo4jUri);
            var nodes = graphDb.GetAllNodes().ToList();

            Assert.AreEqual(7, nodes.Count);
        }

        [TestMethod]
        public void GetAllRelationships()
        {
            var graphDb = new GraphDatabaseService(Neo4jUri);
            var relationships = graphDb.GetAllRelationships().ToList();

            Assert.AreEqual(7, relationships.Count);
        }

        [TestMethod]
        public void FindNeoFriends()
        {            
            var graphDb = new GraphDatabaseService(Neo4jUri);
                        
            var builder = new TraversalBuilder()
                .WithMaxDepth(1000)
                .WithOrder(TraversalOrder.BreadthFirst)
                .WithReturn(BuiltInReturnableEvaluatorType.AllButStartNode)
                .WithRelationship(MyRelationshipTypes.Knows, RelationshipDirection.Out);

            var nodes = neoNode.Traverse(builder);
            var friendNames = nodes.Select(x => x.GetProperty<string>("name")).ToList();
            var expectedFriendNames = new List<string> { "Trinity", "Morpheus", "Cypher", "Agent Smith" };

            friendNames.Sort();
            expectedFriendNames.Sort();

            Assert.IsTrue(expectedFriendNames.SequenceEqual(friendNames));            
        }

        [TestMethod]
        [Ignore]
        public void FindHackers()
        {            
            var graphDb = new GraphDatabaseService(Neo4jUri);
                        
            string jsReturnableEvaluator =            
                @"position.length > 0 && position.lastRelationship() != null && position.lastRelationship().isType('CodedBy');";

            var builder = new TraversalBuilder()
                .WithMaxDepth(1000)
                .WithOrder(TraversalOrder.BreadthFirst)                
                .WithReturn(jsReturnableEvaluator)
                .WithRelationship(MyRelationshipTypes.Knows, RelationshipDirection.Out)
                .WithRelationship(MyRelationshipTypes.CodedBy, RelationshipDirection.Out);

            var nodes = neoNode.Traverse(builder);
            var hackerNames = nodes.Select(x => x.GetProperty<string>("name")).ToList();
        }
    }
}
